package eteam.aps.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import eteam.aps.client.CommonClient;
import eteam.aps.common.R;
import eteam.aps.common.exceptions.BusinessException;
import eteam.aps.common.helper.Helper;
import eteam.aps.common.helper.JsonPage;
import eteam.aps.config.ExcelAdvance;
import eteam.aps.model.dto.ArrivalVouchQueryDto;
import eteam.aps.model.dto.SaleQueryDto;
import eteam.aps.model.export.KV;
import eteam.aps.model.export.model.*;
import eteam.aps.model.export.query.*;
import eteam.aps.service.ExportService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author Ll
 * @since 2024/1/17
 */
@SuppressWarnings("DuplicatedCode")
@RestController
@RequestMapping("/ec")
@Api(tags = "报表")
@AllArgsConstructor
public class ExportController {

    private final ExportService exportService;
    private final CommonClient client;
    private final HttpServletResponse response;

    @PostMapping("av")
    @ApiOperation("到货单导出")
    public void arrivalVouchExport(@RequestBody ArrivalVouchQueryDto arrivalVouchQueryDto) throws Exception {
        if (arrivalVouchQueryDto == null) throw new BusinessException(HttpStatus.BAD_REQUEST, "参数非法异常！");
        exportService.arrivalVouchExport(client.selectUserName(), arrivalVouchQueryDto);
    }

    @PostMapping("so")
    @ApiOperation("销售单导出")
    public void saleOrderExport(@RequestBody SaleQueryDto query) throws Exception {
        if (query == null) throw new BusinessException(HttpStatus.BAD_REQUEST, "参数非法异常！");
        if (Helper.isEmpty(query.getCustomerCode())) query.setCustomerCode(null);
        if (Helper.isEmpty(query.getOrderNumber())) query.setOrderNumber(null);
        if (Helper.isEmpty(query.getHandlerPeople())) query.setHandlerPeople(null);
        if (Helper.isEmpty(query.getLogisticsCode())) query.setLogisticsCode(null);
        if (Helper.isNotEmpty(query.getOrderNumber())) {
            query.setOrderNumber(Helper.likeSql(query.getOrderNumber()));
        }
        if (Helper.isNotEmpty(query.getHandlerPeople())) {
            query.setHandlerPeople(Helper.likeSql(query.getHandlerPeople()));
        }
        if (Helper.isNotEmpty(query.getLogisticsCode())) {
            query.setLogisticsCode(Helper.likeSql(query.getLogisticsCode()));
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("销售单报表", "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        // 查询集合
        List<SaleOrderExport> exports = exportService.saleOrderExport(query);
        // 根据单号进行分组
        Map<String, List<KV<String, Integer>>> orderGroup = exports.stream().map(data -> new KV<>(data.getOrderCode(), 1)).collect(Collectors.groupingBy(KV::getKey));
        // 单号分组的次数
        int orderCodeMerge = orderGroup.isEmpty() ? 0 : exports.size() / orderGroup.size();
        // order开始合并的行
        AtomicInteger orderStart = new AtomicInteger(1);
        // 根据bll单号进行分组
        Map<String, List<KV<String, Integer>>> bllGroup = exports.stream().map(data -> new KV<>(data.getBllId(), 1)).collect(Collectors.groupingBy(KV::getKey));
        // bll分组的次数
        int bllMerge = bllGroup.isEmpty() ? 0 : exports.size() / bllGroup.size();
        // bll开始合并的行
        AtomicInteger bllStart = new AtomicInteger(1);
        // 写excel
        EasyExcel.write(response.getOutputStream(), SaleOrderExport.class).registerWriteHandler(new AbstractMergeStrategy() {
                    @Override
                    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
                        // 当前行
                        int rowIndex = cell.getRowIndex();
                        // 当前列
                        int columnIndex = cell.getColumnIndex();
                        // 合并扫描产品 【满足合并条见】
                        if (bllMerge != 0 && rowIndex % bllMerge == 0 && columnIndex == 17) {
                            int group = bllGroup.get(cell.getRow().getCell(17).getStringCellValue()).size();
                            int size = bllStart.get() + group - 1;
                            for (int index = 13; index <= 17; index++) {
                                CellRangeAddress addresses = new CellRangeAddress(Math.min(bllStart.get(), exports.size()), Math.min(exports.size(), size), index, index);
                                if (addresses.getFirstRow() != addresses.getLastRow()) {
                                    sheet.addMergedRegion(addresses);
                                }
                            }
                            bllStart.addAndGet(group);
                        }
                        // 合并客户信息
                        if (orderCodeMerge != 0 && rowIndex % orderCodeMerge == 0 && columnIndex == 12) {
                            int size = orderStart.get() + orderGroup.get(cell.getRow().getCell(0).getStringCellValue()).size() - 1;
                            for (int index = 0; index <= 12; index++) {
                                CellRangeAddress addresses = new CellRangeAddress(Math.min(orderStart.get(), exports.size()), Math.min(size, exports.size()), index, index);
                                if (addresses.getFirstRow() != addresses.getLastRow()) {
                                    sheet.addMergedRegion(addresses);
                                }
                            }
                            orderStart.addAndGet(size);
                        }
                    }
                }).registerWriteHandler(ExcelAdvance.getStyle())
                .sheet("销售单").doWrite(exports);
    }

    @PostMapping("oo")
    @ApiOperation("销售出库单导出")
    public void outboundOrdersExport(@RequestBody OutboundOrdersQuery query) throws IOException {
        if (Helper.isEmpty(query.getOrderNumber())
                && query.getOrderStartTime() == null
                && query.getOrderEndTime() == null
        ) {
            throw new BusinessException("单号和日期不能都为空!");
        }
        if (query.getOrderStartTime() != null && query.getOrderEndTime() != null) {
            if (query.getOrderStartTime().isAfter(query.getOrderEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        if (Helper.isEmpty(query.getOrderNumber())) {
            query.setOrderNumber(null);
        }
        List<OutboundOrdersExport> exports = exportService.outboundOrdersExport(query);
        String fileName = URLEncoder.encode("发货出库单", "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        try (
                InputStream inputStream = ExportController.class.getClassLoader().getResourceAsStream("out_order.xlsx");
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(inputStream).build();
        ) {
            // 创建一个sheet
            WriteSheet writeSheet = EasyExcel
                    .writerSheet()
                    .build();
            // 填充配置
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(exports, fillConfig, writeSheet);
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("total", exports.size());
            Optional.ofNullable(exports.get(0)).ifPresent(data -> {
                map.put("number", Optional.ofNullable(data.getOrderNumber()).orElse(LocalDate.now().toString()));
                map.put("shipper", Optional.ofNullable(data.getShipper()).orElse("李宝"));
                map.put("logistics", Optional.ofNullable(data.getLogistics()).orElse(""));
            });
            excelWriter.fill(map, writeSheet);
        }
    }

    @PostMapping("oos")
    @ApiOperation("销售出库单查询")
    public R<List<OutboundOrdersExport>> outboundOrdersSelect(@RequestBody OutboundOrdersQuery query) {
        if (Helper.isEmpty(query.getOrderNumber())
                && query.getOrderStartTime() == null
                && query.getOrderEndTime() == null
        ) {
            throw new BusinessException("单号和日期不能都为空!");
        }
        if (query.getOrderStartTime() != null && query.getOrderEndTime() != null) {
            if (query.getOrderStartTime().isAfter(query.getOrderEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        if (Helper.isEmpty(query.getOrderNumber())) {
            query.setOrderNumber(null);
        }
        return R.success(exportService.outboundOrdersExport(query));
    }

    @PostMapping("sdes")
    @ApiOperation("发货数据查询")
    public R<List<ShipmentDataExport>> shipmentDataSelect(@RequestBody ShipmentDataQuery query) {
        if (Helper.isEmpty(query.getOrderNumber()) &&
                query.getStartTime() == null &&
                query.getEndTime() == null &&
                Helper.isEmpty(query.getElectronFlow())) {
            throw new BusinessException("单号、日期以及电子流不能都为空!");
        }
        if (query.getStartTime() != null && query.getEndTime() != null) {
            if (query.getStartTime().isAfter(query.getEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        if (Helper.isEmpty(query.getOrderNumber())) {
            query.setOrderNumber(null);
        }
        if (Helper.isEmpty(query.getElectronFlow())) {
            query.setElectronFlow(null);
        }
        return R.success(exportService.shipmentDataSelect(query));
    }

    @PostMapping("sde")
    @ApiOperation("发货数据导出")
    public void shipmentDataExport(@RequestBody ShipmentDataQuery query) {
        if (Helper.isEmpty(query.getOrderNumber()) &&
                query.getStartTime() == null &&
                query.getEndTime() == null &&
                Helper.isEmpty(query.getElectronFlow())) {
            throw new BusinessException("单号、日期以及电子流不能都为空!");
        }
        if (query.getStartTime() != null && query.getEndTime() != null) {
            if (query.getStartTime().isAfter(query.getEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        if (Helper.isEmpty(query.getOrderNumber())) {
            query.setOrderNumber(null);
        }
        if (Helper.isEmpty(query.getElectronFlow())) {
            query.setElectronFlow(null);
        }
        exportService.shipmentDataExport(query);
    }

    @PostMapping("qe")
    @ApiOperation("质检数据导出")
    public void qualityExport(@RequestBody QualityQuery query) {
        if (query.getStartTime() == null
                && query.getEndTime() == null
                && query.getType() == null) {
            throw new BusinessException("日期和业务类型不能都为空!");
        }
        if (Helper.isEmpty(query.getWpCode())) {
            query.setWpCode(null);
        }
        if (query.getStartTime() != null && query.getEndTime() != null) {
            if (query.getStartTime().isAfter(query.getEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        exportService.qualityExport(query);
    }

    @PostMapping("qes")
    @ApiOperation("质检数据查询")
    public R<List<QualityExport>> qualitySelect(@RequestBody QualityQuery query) {
        if (query.getStartTime() == null
                && query.getEndTime() == null
                && query.getType() == null
                && query.getWpCode() == null
        ) {
            throw new BusinessException("日期、业务类型以及工序不能都为空!");
        }
        if (Helper.isEmpty(query.getWpCode())) {
            query.setWpCode(null);
        }
        if (query.getStartTime() != null && query.getEndTime() != null) {
            if (query.getStartTime().isAfter(query.getEndTime())) {
                throw new BusinessException("开始时间不能大于结束时间!");
            }
        }
        return R.success(exportService.qualitySelect(query));
    }

    @PostMapping("inv")
    @ApiOperation("现存量清单")
    @ApiImplicitParam(value = "现存量查询", required = true)
    public void inventoryExport(@RequestBody InventoryQuery query) throws Exception {
        int code = 0;
        if (Helper.isEmpty(query.getWhCode())) {
            query.setWhCode(null);
            code++;
        }
        if (Helper.isEmpty(query.getInvCode())) {
            query.setInvCode(null);
            code++;
        }
        if (Helper.isEmpty(query.getBatch())) {
            query.setBatch(null);
            code++;
        }
        if (code > 2) {
            throw new BusinessException("仓库代码、存货编码、批号不能都为空!");
        }
        exportService.inventoryExport(query);
    }

    @PostMapping("invs")
    @ApiOperation("现存量查询")
    @ApiImplicitParam(value = "现存量查询", required = true)
    public R<JsonPage<InventoryExport>> inventorySelect(@RequestBody InventoryQuery query) throws Exception {
        int code = 0;
        if (Helper.isEmpty(query.getWhCode())) {
            query.setWhCode(null);
            code++;
        }
        if (Helper.isEmpty(query.getInvCode())) {
            query.setInvCode(null);
            code++;
        }
        if (Helper.isEmpty(query.getBatch())) {
            query.setBatch(null);
            code++;
        }
        if (code > 2) {
            throw new BusinessException("仓库代码、存货编码、批号不能都为空!");
        }
        return R.success(exportService.inventorySelect(query));
    }

    @PostMapping("dns")
    @ApiOperation("送货单查询")
    @ApiImplicitParam(value = "送货单查询", required = true)
    public R<InvoicesExport> deliveryNoteSelect(@RequestBody InvoicesQuery query) throws Exception {
        if (Helper.isEmpty(query.getOrderNumber())) {
            throw new BusinessException("单号不能为空!");
        }
        return R.success(exportService.deliveryNoteSelect(query));
    }

    @PostMapping("dne")
    @ApiOperation("送货单清单")
    @ApiImplicitParam(value = "送货单查询", required = true)
    public void deliveryNoteExport(@RequestBody InvoicesQuery query) throws Exception {
        if (Helper.isEmpty(query.getOrderNumber())) {
            throw new BusinessException("单号不能为空!");
        }
        InvoicesExport export = exportService.deliveryNoteSelect(query);
        String fileName = URLEncoder.encode("送货单", "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        try (
                InputStream inputStream = ExportController.class.getClassLoader().getResourceAsStream("sale_order.xlsx");
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(inputStream).build();
        ) {
            // 创建一个sheet
            WriteSheet writeSheet = EasyExcel
                    .writerSheet()
                    .build();
            // 填充配置
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(export.getBody(), fillConfig, writeSheet);
            excelWriter.fill(export.getHead(), writeSheet);
        }
    }


    @PostMapping("psJsp")
    @ApiOperation("任务令产品编码状态清单分页查询")
    public R<JsonPage<ProductSerialExport>> productSerialJsp(@RequestBody ProductSerialQuery productSerialQuery) {
        return R.success(exportService.productSerialJsp(productSerialQuery));
    }

    @PostMapping("ps")
    @ApiOperation("任务令产品编码状态清单")
    public void productSerialExport(@RequestBody ProductSerialQuery productSerialQuery) {
        exportService.productSerialExport(productSerialQuery);
    }

    @PostMapping("pwpJsp")
    @ApiOperation("任务令产品编码工序状态分页查询")
    public R<JsonPage<ProductWorkProcessingExport>> productWorkProcessingJsp(@RequestBody ProductWorkProcessingQuery processingQuery) {
        return R.success(exportService.productWorkProcessingJsp(processingQuery));
    }

    @PostMapping("pwp")
    @ApiOperation("任务令产品编码工序状态清单")
    public void productWorkProcessingExport(@RequestBody ProductWorkProcessingQuery processingQuery) {
        exportService.productWorkProcessingExport(processingQuery);
    }

    @PostMapping("piJsp")
    @ApiOperation("任务令产品材料序列分页查询")
    public R<JsonPage<ProductInvExport>> productInvJsp(@RequestBody ProductInvQuery productInvQuery) {
        return R.success(exportService.productInvJsp(productInvQuery));
    }

    @PostMapping("pi")
    @ApiOperation("任务令产品材料序列清单")
    public void productInvExport(@RequestBody ProductInvQuery productInvQuery) {
        exportService.productInvExport(productInvQuery);
    }

}
